int MAX=300;

boolean combine(float p1x,float p1y,int p1size,float p2x,float p2y,int p2size) {
  if ((absD(p1x-width/2)<p1size)||(absD(p1y-height/2)<p1size)) return false;
  if ((absD(p2x-width/2)<p2size)||(absD(p2y-height/2)<p2size)) return false;
  float dif= sqrt((p2x-p1x)*(p2x-p1x) + (p2y-p1y)*(p2y-p1y));
  if (dif<=p1size+p2size) return true; 
  return false;
}

float dgRAND(float minVal,float maxVal) {
  float retVal = minVal + random(maxVal-minVal);
  return retVal;
}

class dgParticle {
  float x; // initial position x
  float y; // initial position y
  float speed[]; //SPEED
  float direction[]; //DIRECTION
  int colorP[];
  int move;
  int sizeP;
  dgParticle() {}
  dgParticle(int windowW,int windowH) {
    this.x = windowW/2;
    this.y = windowH/2;
    this.move = windowW/20;
    this.sizeP = windowW/40;
    this.colorP = new int[]{int(random(255)),int(random(255)),int(random(255))};
    this.speed = new float[]{dgRAND(-this.move/2,this.move/2),dgRAND(-this.move/2,this.move/2),0};
    this.direction = new float[]{random(1),random(1),0};
    DogaMakeUnitVector(this.direction);
  }
  void createParticle(int windowW,int windowH) {
    this.x = windowW/2;
    this.y = windowH/2;
    this.sizeP = windowW/40;
    this.colorP = new int[]{int(random(255)),int(random(255)),int(random(255))};
    this.speed = new float[]{dgRAND(-this.move/2,this.move/2),dgRAND(-this.move/2,this.move/2),0};
    this.direction = new float[]{random(1),random(1),0};
    DogaMakeUnitVector(this.direction);
  }
  void drawIt(int windowW,int windowH) {
//    fill(this.direction[0]*255,255,this.direction[1]*255);
    fill(this.colorP[0],this.colorP[1],this.colorP[2]);
    ellipseMode(CENTER);
    ellipse(this.x,this.y,this.sizeP,this.sizeP);
  }
  void moveIt(int windowW,int windowH) {
    if ((this.x<1)&&(this.speed[0]<0)) {this.speed[0] *= -1;}
    if ((this.y<1)&&(this.speed[1]<0)) {this.speed[1] *= -1;}
    if ((this.x>windowW-1)&&(this.speed[0]>0)) {this.speed[0] *= -1;}
    if ((this.y>windowH-1)&&(this.speed[1]>0)) {this.speed[1] *= -1;}
    this.x += this.speed[0]*this.direction[0];
    this.y += this.speed[1]*this.direction[1];
  }
}

class dgParticleSystem {
  int numOfParticles;
  dgParticle[] particles;
  int numOfGroups;
  int[][] particleGroups; //[index of the group(lets call it 'i')][index of the group element(0 to howManyInAGroup[i])] --> index of the particle
  int[] howManyInAGroup;  //[index of the group(lets call it 'i')]--> tells how many is there inside the group
  int[] groupOfAParticle; //[index of the particle(0 to numOfParticles)]-->gives the index number of the group which it belongs to. if not in group iti is -1
  boolean[] particleActive;
  dgParticleSystem() {}
  dgParticleSystem(int numOfParticlesToCreate,int windowW,int windowH) {
    int i=0;
    numOfGroups=0;
    particleGroups = new int[MAX/2][];
    howManyInAGroup = new int[MAX/2];
    groupOfAParticle = new int[MAX];
    particles = new dgParticle[MAX];
    particleActive = new boolean[MAX];
    for (i=0;i<MAX/2;i++) howManyInAGroup[i] = 0;
    for (i=0;i<MAX;i++) groupOfAParticle[i] = -1;
    for (i=0;i<numOfParticlesToCreate;i++) {
      particles[i] = new dgParticle(windowW,windowH);
      particleActive[i] = true;
    }
    for (i=numOfParticlesToCreate;i<MAX;i++) particleActive[i] = false;
    numOfParticles = numOfParticlesToCreate;
  }
  void moveThem(int windowW,int windowH) {
    boolean recreate=false;
    boolean evaluated[] = new boolean[numOfParticles];
    for (int i=0;i<numOfParticles;i++) evaluated[i]=false;
    
    for (int i=0;i<numOfParticles;i++) {
      if ((particleActive[i])&&(!evaluated[i])) {//if not evaluated and active then
        for (int j=0;j<numOfParticles;j++) {
          if ((particleActive[j])&&combine(particles[i].x,particles[i].y,particles[i].sizeP,particles[j].x,particles[j].y,particles[j].sizeP)) {
            if () {//if the particle is in a group and is near to another one which is also a group
            
            }
            else if {//if the particle has no group yet
            }
            particles[i].speed[0] = (particles[i].speed[0] + particles[j].speed[0])/2;
            particles[i].speed[1] = (particles[i].speed[1] + particles[j].speed[1])/2;
            particles[i].direction[0] = (particles[i].direction[0] + particles[j].direction[0])/2;
            particles[i].direction[1] = (particles[i].direction[1] + particles[j].direction[1])/2;
            particles[j].speed[0] = particles[i].speed[0];
            particles[j].speed[1] = particles[i].speed[1];
            particles[j].direction[0] = particles[i].direction[0];
            particles[j].direction[1] = particles[i].direction[1];
          }
        }
      }
    }
    for (int i=0;i<numOfParticles;i++) {
      particles[i].moveIt(windowW,windowH);
      if (absD(particles[i].speed[0])+absD(particles[i].speed[1])<particles[i].move/2) {
        particles[i].createParticle(windowW,windowH);
        recreate = true;
      }
      if ((!recreate)&&(numOfParticles<MAX)) {
        particles[numOfParticles] = new dgParticle(windowW,windowH);
        particleActive[numOfParticles] = true;
        numOfParticles++;
      }
    }   
  }
  void drawThem(int windowW,int windowH) {
    boolean recreate=false;
    for (int i=0;i<numOfParticles;i++)
      if (particleActive[i])
        particles[i].drawIt(windowW,windowH);
  }
}

dgParticleSystem myParticleSystem;
int numOfParts=1;
void setup () {
  int i=0;
  size(400,400);
  myParticleSystem = new dgParticleSystem(numOfParts,width,height);
  PFont myFont = createFont("verdana", 24);
  textFont(myFont);
}

void draw() {
  int i=0;
  background(0);
  myParticleSystem.moveThem(width,height);
  myParticleSystem.drawThem(width,height);
  fill(255);
  text(myParticleSystem.numOfParticles,width/2,height/2);  
}

float absD(float x) {
  if (x>=0) return x;
  return -x;
}
float DogaDotProduct(float V1[],float V2[]) {return V1[0]*V2[0]+V1[1]*V2[1]+V1[2]*V2[2];}
float DogaMakeUnitVector(float V[]) {
  float w=0;
  w = sqrt(DogaDotProduct(V,V));
  if (w!=0) {
    V[0] = V[0]/w;
    V[1] = V[1]/w;
    V[2] = V[2]/w;
  }
  else {
    V[0] = 0;
    V[1] = 0;
    V[2] = 0;
  }
  return w;
}

 //   if (noise(this.way[0]*this.way[1],this.x*this.y,this.inc[0]*this.inc[1])>0.5) this.way[0] += 0.2;
 //   else this.way[1] += 0.2;
 //   DogaMakeUnitVector(this.way);
 //   this.incX += this.way[0];
 //   this.incY += this.way[1];
